home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / Mail / aux.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-09  |  11.7 KB  |  634 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)aux.c    5.16 (Berkeley) 12/23/88";
  20. #endif /* not lint */
  21.  
  22. #include "rcv.h"
  23. #include <sys/stat.h>
  24. #include <sys/time.h>
  25.  
  26. /*
  27.  * Mail -- a mail program
  28.  *
  29.  * Auxiliary functions.
  30.  */
  31.  
  32. /*
  33.  * Return a pointer to a dynamic copy of the argument.
  34.  */
  35. char *
  36. savestr(str)
  37.     char *str;
  38. {
  39.     char *new;
  40.     int size = strlen(str) + 1;
  41.  
  42.     if ((new = salloc(size)) != NOSTR)
  43.         bcopy(str, new, size);
  44.     return new;
  45. }
  46.  
  47. /*
  48.  * Announce a fatal error and die.
  49.  */
  50.  
  51. /*VARARGS1*/
  52. panic(fmt, a, b)
  53.     char *fmt;
  54. {
  55.     fprintf(stderr, "panic: ");
  56.     fprintf(stderr, fmt, a, b);
  57.     putc('\n', stderr);
  58.     exit(1);
  59. }
  60.  
  61. /*
  62.  * Touch the named message by setting its MTOUCH flag.
  63.  * Touched messages have the effect of not being sent
  64.  * back to the system mailbox on exit.
  65.  */
  66. touch(mp)
  67.     register struct message *mp;
  68. {
  69.  
  70.     mp->m_flag |= MTOUCH;
  71.     if ((mp->m_flag & MREAD) == 0)
  72.         mp->m_flag |= MREAD|MSTATUS;
  73. }
  74.  
  75. /*
  76.  * Test to see if the passed file name is a directory.
  77.  * Return true if it is.
  78.  */
  79. isdir(name)
  80.     char name[];
  81. {
  82.     struct stat sbuf;
  83.  
  84.     if (stat(name, &sbuf) < 0)
  85.         return(0);
  86.     return((sbuf.st_mode & S_IFMT) == S_IFDIR);
  87. }
  88.  
  89. /*
  90.  * Count the number of arguments in the given string raw list.
  91.  */
  92. argcount(argv)
  93.     char **argv;
  94. {
  95.     register char **ap;
  96.  
  97.     for (ap = argv; *ap++ != NOSTR;)
  98.         ;    
  99.     return ap - argv - 1;
  100. }
  101.  
  102. /*
  103.  * Return the desired header line from the passed message
  104.  * pointer (or NOSTR if the desired header field is not available).
  105.  */
  106. char *
  107. hfield(field, mp)
  108.     char field[];
  109.     struct message *mp;
  110. {
  111.     register FILE *ibuf;
  112.     char linebuf[LINESIZE];
  113.     register int lc;
  114.     register char *hfield;
  115.     char *colon;
  116.  
  117.     ibuf = setinput(mp);
  118.     if ((lc = mp->m_lines - 1) < 0)
  119.         return NOSTR;
  120.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  121.         return NOSTR;
  122.     while (lc > 0) {
  123.         if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
  124.             return NOSTR;
  125.         if (hfield = ishfield(linebuf, colon, field))
  126.             return savestr(hfield);
  127.     }
  128.     return NOSTR;
  129. }
  130.  
  131. /*
  132.  * Return the next header field found in the given message.
  133.  * Return >= 0 if something found, < 0 elsewise.
  134.  * "colon" is set to point to the colon in the header.
  135.  * Must deal with \ continuations & other such fraud.
  136.  */
  137. gethfield(f, linebuf, rem, colon)
  138.     register FILE *f;
  139.     char linebuf[];
  140.     register int rem;
  141.     char **colon;
  142. {
  143.     char line2[LINESIZE];
  144.     register char *cp, *cp2;
  145.     register int c;
  146.  
  147.     for (;;) {
  148.         if (--rem < 0)
  149.             return -1;
  150.         if ((c = readline(f, linebuf, LINESIZE)) <= 0)
  151.             return -1;
  152.         for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
  153.              cp++)
  154.             ;
  155.         if (*cp != ':' || cp == linebuf)
  156.             continue;
  157.         /*
  158.          * I guess we got a headline.
  159.          * Handle wraparounding
  160.          */
  161.         *colon = cp;
  162.         cp = linebuf + c;
  163.         for (;;) {
  164.             while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
  165.                 ;
  166.             cp++;
  167.             if (rem <= 0)
  168.                 break;
  169.             ungetc(c = getc(f), f);
  170.             if (c != ' ' && c != '\t')
  171.                 break;
  172.             if ((c = readline(f, line2, LINESIZE)) < 0)
  173.                 break;
  174.             rem--;
  175.             for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
  176.                 ;
  177.             c -= cp2 - line2;
  178.             if (cp + c >= linebuf + LINESIZE - 2)
  179.                 break;
  180.             *cp++ = ' ';
  181.             bcopy(cp2, cp, c);
  182.             cp += c;
  183.         }
  184.         *cp = 0;
  185.         return rem;
  186.     }
  187.     /* NOTREACHED */
  188. }
  189.  
  190. /*
  191.  * Check whether the passed line is a header line of
  192.  * the desired breed.  Return the field body, or 0.
  193.  */
  194.  
  195. char*
  196. ishfield(linebuf, colon, field)
  197.     char linebuf[], field[];
  198.     char *colon;
  199. {
  200.     register char *cp = colon;
  201.  
  202.     *cp = 0;
  203.     if (strcasecmp(linebuf, field) != 0) {
  204.         *cp = ':';
  205.         return 0;
  206.     }
  207.     *cp = ':';
  208.     for (cp++; *cp == ' ' || *cp == '\t'; cp++)
  209.         ;
  210.     return cp;
  211. }
  212.  
  213. /*
  214.  * Copy a string, lowercasing it as we go.
  215.  */
  216. istrcpy(dest, src)
  217.     register char *dest, *src;
  218. {
  219.  
  220.     do {
  221.         if (isupper(*src))
  222.             *dest++ = tolower(*src);
  223.         else
  224.             *dest++ = *src;
  225.     } while (*src++ != 0);
  226. }
  227.  
  228. /*
  229.  * The following code deals with input stacking to do source
  230.  * commands.  All but the current file pointer are saved on
  231.  * the stack.
  232.  */
  233.  
  234. static    int    ssp;            /* Top of file stack */
  235. struct sstack {
  236.     FILE    *s_file;        /* File we were in. */
  237.     int    s_cond;            /* Saved state of conditionals */
  238.     int    s_loading;        /* Loading .mailrc, etc. */
  239. } sstack[NOFILE];
  240.  
  241. /*
  242.  * Pushdown current input file and switch to a new one.
  243.  * Set the global flag "sourcing" so that others will realize
  244.  * that they are no longer reading from a tty (in all probability).
  245.  */
  246. source(arglist)
  247.     char **arglist;
  248. {
  249.     FILE *fi;
  250.     char *cp;
  251.  
  252.     if ((cp = expand(*arglist)) == NOSTR)
  253.         return(1);
  254.     if ((fi = fopen(cp, "r")) == NULL) {
  255.         perror(cp);
  256.         return(1);
  257.     }
  258.     if (ssp >= NOFILE - 1) {
  259.         printf("Too much \"sourcing\" going on.\n");
  260.         fclose(fi);
  261.         return(1);
  262.     }
  263.     sstack[ssp].s_file = input;
  264.     sstack[ssp].s_cond = cond;
  265.     sstack[ssp].s_loading = loading;
  266.     ssp++;
  267.     loading = 0;
  268.     cond = CANY;
  269.     input = fi;
  270.     sourcing++;
  271.     return(0);
  272. }
  273.  
  274. /*
  275.  * Pop the current input back to the previous level.
  276.  * Update the "sourcing" flag as appropriate.
  277.  */
  278. unstack()
  279. {
  280.     if (ssp <= 0) {
  281.         printf("\"Source\" stack over-pop.\n");
  282.         sourcing = 0;
  283.         return(1);
  284.     }
  285.     fclose(input);
  286.     if (cond != CANY)
  287.         printf("Unmatched \"if\"\n");
  288.     ssp--;
  289.     cond = sstack[ssp].s_cond;
  290.     loading = sstack[ssp].s_loading;
  291.     input = sstack[ssp].s_file;
  292.     if (ssp == 0)
  293.         sourcing = loading;
  294.     return(0);
  295. }
  296.  
  297. /*
  298.  * Touch the indicated file.
  299.  * This is nifty for the shell.
  300.  */
  301. alter(name)
  302.     char name[];
  303. {
  304.     struct stat statb;
  305.     long time();
  306.     struct timeval tvp[2];
  307.  
  308.     if (stat(name, &statb) < 0)
  309.         return;
  310.     /*
  311.      * With a distributed file system we can't count on our time()
  312.      * being the same as the server's, so we just set the access
  313.      * time to be greater than the modify time.  The old code
  314.      * used to set the access time to one second greater than time(),
  315.      * which still might be less than the server's modify time.
  316.      */
  317.     tvp[0].tv_sec = (long) statb.st_mtime + 1;
  318.     tvp[0].tv_usec = 0;
  319.     tvp[1].tv_sec = (long) statb.st_mtime;
  320.     tvp[1].tv_usec = 0;
  321.     utimes(name, tvp);
  322. }
  323.  
  324. /*
  325.  * Examine the passed line buffer and
  326.  * return true if it is all blanks and tabs.
  327.  */
  328. blankline(linebuf)
  329.     char linebuf[];
  330. {
  331.     register char *cp;
  332.  
  333.     for (cp = linebuf; *cp; cp++)
  334.         if (*cp != ' ' && *cp != '\t')
  335.             return(0);
  336.     return(1);
  337. }
  338.  
  339. /*
  340.  * Get sender's name from this message.  If the message has
  341.  * a bunch of arpanet stuff in it, we may have to skin the name
  342.  * before returning it.
  343.  */
  344. char *
  345. nameof(mp, reptype)
  346.     register struct message *mp;
  347. {
  348.     register char *cp, *cp2;
  349.  
  350.     cp = skin(name1(mp, reptype));
  351.     if (reptype != 0 || charcount(cp, '!') < 2)
  352.         return(cp);
  353.     cp2 = rindex(cp, '!');
  354.     cp2--;
  355.     while (cp2 > cp && *cp2 != '!')
  356.         cp2--;
  357.     if (*cp2 == '!')
  358.         return(cp2 + 1);
  359.     return(cp);
  360. }
  361.  
  362. /*
  363.  * Skin an arpa net address according to the RFC 822 interpretation
  364.  * of "host-phrase."
  365.  */
  366. char *
  367. skin(name)
  368.     char *name;
  369. {
  370.     register int c;
  371.     register char *cp, *cp2;
  372.     char *bufend;
  373.     int gotlt, lastsp;
  374.     char nbuf[BUFSIZ];
  375.     int nesting;
  376.  
  377.     if (name == NOSTR)
  378.         return(NOSTR);
  379.     if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
  380.         && index(name, ' ') == NOSTR)
  381.         return(name);
  382.     gotlt = 0;
  383.     lastsp = 0;
  384.     bufend = nbuf;
  385.     for (cp = name, cp2 = bufend; c = *cp++; ) {
  386.         switch (c) {
  387.         case '(':
  388.             /*
  389.              * Start of a "comment".
  390.              * Ignore it.
  391.              */
  392.             nesting = 1;
  393.             while ((c = *cp) != 0) {
  394.                 cp++;
  395.                 switch (c) {
  396.                 case '\\':
  397.                     if (*cp == 0)
  398.                         goto outcm;
  399.                     cp++;
  400.                     break;
  401.                 case '(':
  402.                     nesting++;
  403.                     break;
  404.  
  405.                 case ')':
  406.                     --nesting;
  407.                     break;
  408.                 }
  409.  
  410.                 if (nesting <= 0)
  411.                     break;
  412.             }
  413.         outcm:
  414.             lastsp = 0;
  415.             break;
  416.  
  417.         case '"':
  418.             /*
  419.              * Start of a "quoted-string".
  420.              * Copy it in its entirety.
  421.              */
  422.             while ((c = *cp) != 0) {
  423.                 cp++;
  424.                 switch (c) {
  425.                 case '\\':
  426.                     if ((c = *cp) == 0)
  427.                         goto outqs;
  428.                     cp++;
  429.                     break;
  430.                 case '"':
  431.                     goto outqs;
  432.                 }
  433.                 *cp2++ = c;
  434.             }
  435.         outqs:
  436.             lastsp = 0;
  437.             break;
  438.  
  439.         case ' ':
  440.             if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
  441.                 cp += 3, *cp2++ = '@';
  442.             else
  443.             if (cp[0] == '@' && cp[1] == ' ')
  444.                 cp += 2, *cp2++ = '@';
  445.             else
  446.                 lastsp = 1;
  447.             break;
  448.  
  449.         case '<':
  450.             cp2 = bufend;
  451.             gotlt++;
  452.             lastsp = 0;
  453.             break;
  454.  
  455.         case '>':
  456.             if (gotlt) {
  457.                 gotlt = 0;
  458.                 while (*cp != ',' && *cp != 0)
  459.                     cp++;
  460.                 if (*cp == 0 )
  461.                     goto done;
  462.                 *cp2++ = ',';
  463.                 *cp2++ = ' ';
  464.                 bufend = cp2;
  465.                 break;
  466.             }
  467.  
  468.             /* Fall into . . . */
  469.  
  470.         default:
  471.             if (lastsp) {
  472.                 lastsp = 0;
  473.                 *cp2++ = ' ';
  474.             }
  475.             *cp2++ = c;
  476.             break;
  477.         }
  478.     }
  479. done:
  480.     *cp2 = 0;
  481.  
  482.     return(savestr(nbuf));
  483. }
  484.  
  485. /*
  486.  * Fetch the sender's name from the passed message.
  487.  * Reptype can be
  488.  *    0 -- get sender's name for display purposes
  489.  *    1 -- get sender's name for reply
  490.  *    2 -- get sender's name for Reply
  491.  */
  492. char *
  493. name1(mp, reptype)
  494.     register struct message *mp;
  495. {
  496.     char namebuf[LINESIZE];
  497.     char linebuf[LINESIZE];
  498.     register char *cp, *cp2;
  499.     register FILE *ibuf;
  500.     int first = 1;
  501.  
  502.     if ((cp = hfield("from", mp)) != NOSTR)
  503.         return cp;
  504.     if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
  505.         return cp;
  506.     ibuf = setinput(mp);
  507.     namebuf[0] = 0;
  508.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  509.         return(savestr(namebuf));
  510. newname:
  511.     for (cp = linebuf; *cp && *cp != ' '; cp++)
  512.         ;
  513.     for (; *cp == ' ' || *cp == '\t'; cp++)
  514.         ;
  515.     for (cp2 = &namebuf[strlen(namebuf)];
  516.          *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
  517.         *cp2++ = *cp++;
  518.     *cp2 = '\0';
  519.     if (readline(ibuf, linebuf, LINESIZE) < 0)
  520.         return(savestr(namebuf));
  521.     if ((cp = index(linebuf, 'F')) == NULL)
  522.         return(savestr(namebuf));
  523.     if (strncmp(cp, "From", 4) != 0)
  524.         return(savestr(namebuf));
  525.     while ((cp = index(cp, 'r')) != NULL) {
  526.         if (strncmp(cp, "remote", 6) == 0) {
  527.             if ((cp = index(cp, 'f')) == NULL)
  528.                 break;
  529.             if (strncmp(cp, "from", 4) != 0)
  530.                 break;
  531.             if ((cp = index(cp, ' ')) == NULL)
  532.                 break;
  533.             cp++;
  534.             if (first) {
  535.                 strcpy(namebuf, cp);
  536.                 first = 0;
  537.             } else
  538.                 strcpy(rindex(namebuf, '!')+1, cp);
  539.             strcat(namebuf, "!");
  540.             goto newname;
  541.         }
  542.         cp++;
  543.     }
  544.     return(savestr(namebuf));
  545. }
  546.  
  547. /*
  548.  * Count the occurances of c in str
  549.  */
  550. charcount(str, c)
  551.     char *str;
  552. {
  553.     register char *cp;
  554.     register int i;
  555.  
  556.     for (i = 0, cp = str; *cp; cp++)
  557.         if (*cp == c)
  558.             i++;
  559.     return(i);
  560. }
  561.  
  562. /*
  563.  * Are any of the characters in the two strings the same?
  564.  */
  565. anyof(s1, s2)
  566.     register char *s1, *s2;
  567. {
  568.  
  569.     while (*s1)
  570.         if (index(s2, *s1++))
  571.             return 1;
  572.     return 0;
  573. }
  574.  
  575. /*
  576.  * Convert c to upper case
  577.  */
  578. raise(c)
  579.     register c;
  580. {
  581.  
  582.     if (islower(c))
  583.         return toupper(c);
  584.     return c;
  585. }
  586.  
  587. /*
  588.  * Copy s1 to s2, return pointer to null in s2.
  589.  */
  590. char *
  591. copy(s1, s2)
  592.     register char *s1, *s2;
  593. {
  594.  
  595.     while (*s2++ = *s1++)
  596.         ;
  597.     return s2 - 1;
  598. }
  599.  
  600. /*
  601.  * See if the given header field is supposed to be ignored.
  602.  */
  603. isign(field, ignore)
  604.     char *field;
  605.     struct ignoretab ignore[2];
  606. {
  607.     char realfld[BUFSIZ];
  608.  
  609.     if (ignore == ignoreall)
  610.         return 1;
  611.     /*
  612.      * Lower-case the string, so that "Status" and "status"
  613.      * will hash to the same place.
  614.      */
  615.     istrcpy(realfld, field);
  616.     if (ignore[1].i_count > 0)
  617.         return (!member(realfld, ignore + 1));
  618.     else
  619.         return (member(realfld, ignore));
  620. }
  621.  
  622. member(realfield, table)
  623.     register char *realfield;
  624.     struct ignoretab *table;
  625. {
  626.     register struct ignore *igp;
  627.  
  628.     for (igp = table->i_head[hash(realfield)]; igp != 0; igp = igp->i_link)
  629.         if (*igp->i_field == *realfield &&
  630.             equal(igp->i_field, realfield))
  631.             return (1);
  632.     return (0);
  633. }
  634.